package com.csizg.facemodel.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import com.csizg.facemodel.BuildConfig;
import com.csizg.facemodel.R;
import com.csizg.facemodel.tracker.DetectionBasedTracker;
import com.csizg.facemodel.util.CompareResult;
import com.csizg.facemodel.util.FaceFileUtil;
import com.csizg.facemodel.util.FaceUtil;
import com.csizg.facemodel.util.RawUtil;
import java.io.File;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CsizgCameraView;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

/**
 * 竖屏识别 图片对比方案
 *
 * @author haohao(ronghao3508@gmail.com) on 2018/5/7 17:51
 * @version v1.0
 */
public class MyVCameraView extends CsizgCameraView
        implements CameraBridgeViewBase.CvCameraViewListener2 {

    public static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);
    public static final int JAVA_DETECTOR = 0;
    public static final int NATIVE_DETECTOR = 1;
    public static final String TAG = "MyVCameraView";

    private static final String FACE1 = "Hface1";
    private static final String FACE2 = "currentface";
    public int mDetectorType = NATIVE_DETECTOR;
    public float mRelativeFaceSize = 0.1f;
    public int mAbsoluteFaceSize = 0;
    public CascadeClassifier mJavaDetector;
    public DetectionBasedTracker mNativeDetector;
    private Mat mRgba;
    private Mat mGray;
    private Mat Matlin;
    private Mat gMatlin;
    private Size mNarrowSize;
    private Mat mCache90Mat;
    private ICompareListener iCompareListener;
    private IFaceShowListener iFaceShowListener;
    private File mCascadeFile;
    private boolean captureFace;
    private boolean compareFace;

    private Bitmap mCacheBitmap;

    public MyVCameraView(Context context, int cameraId) {
        super(context, cameraId);
        init();
    }

    public MyVCameraView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setCvCameraViewListener(this);
        disableView();
        setCameraIndex(CAMERA_ID_FRONT);
        setMinFaceSize(0.1f);
        enableView();
    }

    public void switchCamera() {
        disableView();
        setCameraIndex(mCameraIndex == CAMERA_ID_BACK ? CAMERA_ID_FRONT : CAMERA_ID_BACK);
        setMinFaceSize(0.1f);
        enableView();
    }

    @Override
    public void onCameraViewStarted(int width, int height) {
        mGray = new Mat();
        mRgba = new Mat();
        mCache90Mat = new Mat();

        gMatlin = new Mat();
        Matlin = new Mat();

        // height = height - getStausBarHeight(this) - getVirtualBarHeight(this);

        float mScale = (float) height / (float) 540;
        mCacheBitmap =
                Bitmap.createBitmap((int) ((float) width / mScale), (int) ((float) height / mScale),
                        Bitmap.Config.ARGB_4444);
        Utils.bitmapToMat(mCacheBitmap, mCache90Mat);
        Core.rotate(mCache90Mat, mCache90Mat, Core.ROTATE_90_CLOCKWISE);

        if (BuildConfig.DEBUG) {
            System.out.println("mScale = "
                    + mScale
                    + "，width = "
                    + mCacheBitmap.getWidth()
                    + "，height = "
                    + mCacheBitmap.getHeight());
        }

        mNarrowSize = new Size(mCacheBitmap.getWidth(), mCacheBitmap.getHeight()); // 设置新图片的大小

        mCascadeFile = RawUtil.getRawFile(getContext(), R.raw.lbpcascade_frontalface);
        setCascadeFile(mCascadeFile);
        mCascadeFile.delete();
    }

    @Override
    public void onCameraViewStopped() {
        mGray.release();
        mRgba.release();
    }

    @Override
    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        Mat rgba = inputFrame.rgba();

        mGray = inputFrame.gray();
        Mat narrowMat = new Mat(mNarrowSize, CvType.CV_8UC1);
        Imgproc.resize(mGray, narrowMat, mNarrowSize);
        Imgproc.resize(rgba, rgba, mNarrowSize);

        mCache90Mat.copyTo(Matlin);
        //使前置的图像也是正的
        if (getCameraIndex() == CameraBridgeViewBase.CAMERA_ID_FRONT) {
            Core.flip(narrowMat, narrowMat, 1);

            Core.flip(rgba, rgba, 1);
        }
        if (mAbsoluteFaceSize == 0) {
            int height = narrowMat.rows();
            if (Math.round(height * mRelativeFaceSize) > 0) {
                mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
            }
            if (mNativeDetector != null) {
                mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
            }
        }

        MatOfRect faces = new MatOfRect();
        if (getDisplayOrientation() == 270) {
            Core.rotate(narrowMat, gMatlin, Core.ROTATE_90_COUNTERCLOCKWISE);
            Core.rotate(rgba, rgba, Core.ROTATE_90_COUNTERCLOCKWISE);
        } else {
            Core.rotate(narrowMat, gMatlin, Core.ROTATE_90_CLOCKWISE);
            Core.rotate(rgba, rgba, Core.ROTATE_90_CLOCKWISE);
        }
        if (mNativeDetector != null) {
            mNativeDetector.detect(gMatlin, faces);
        }
        Rect[] faceArray = faces.toArray();
        for (Rect rect : faceArray) {
            Imgproc.rectangle(Matlin, rect.tl(), rect.br(), FACE_RECT_COLOR, 1);
        }
        Core.rotate(Matlin, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE);

        deliverAndDrawFrame(faceArray.length, mRgba);

        for (Rect rect : faceArray) {
            onFace(rgba, rect);
        }
        return mRgba;
    }

    protected void deliverAndDrawFrame(int count, Mat modified) {

        boolean bmpValid = true;
        if (modified != null) {
            try {
                Utils.matToBitmap(modified, mCacheBitmap, true);
            } catch (Exception e) {
                bmpValid = false;
            }
        }
        if (count > 0 && bmpValid && mCacheBitmap != null) {
            if (iFaceShowListener != null) {
                iFaceShowListener.onShow(mCacheBitmap);
            }
        } else {
            if (iFaceShowListener != null) {
                iFaceShowListener.onShow(null);
            }
        }
    }

    public void setMinFaceSize(float faceSize) {
        mRelativeFaceSize = faceSize;
        mAbsoluteFaceSize = 0;
    }

    public void setCascadeFile(File mCascadeFile) {
        mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);
    }

    public void setCaptureFace() {
        captureFace = true;
    }

    public void setCompareFace() {
        compareFace = true;
    }

    public void onFace(Mat mat, Rect rect) {
        if (captureFace) {
            // 保存人脸信息
            final boolean isFinish = FaceUtil.saveImage(getContext(), mat, rect, FACE1);
            if (iCompareListener != null) {

                post(new Runnable() {
                    @Override
                    public void run() {
                        if (iCompareListener != null) {
                            iCompareListener.onCapture(isFinish);
                        }
                    }
                });
            }

            captureFace = false;
        }

        if (compareFace) {
            //对比
            if (iCompareListener != null) {
                FaceUtil.saveImage(getContext(), mat, rect, FACE2);
                final CompareResult cmp = FaceUtil.compareForFiles(getContext(), FACE2, 85);
                post(new Runnable() {
                    @Override
                    public void run() {
                        if (iCompareListener != null) {
                            iCompareListener.onCompare(cmp);
                        }
                    }
                });
            }

            compareFace = false;
        }
    }

    public void setICompareListener(ICompareListener iCompareListener) {
        this.iCompareListener = iCompareListener;
    }

    public void setIFaceShowListener(IFaceShowListener iFaceShowListener) {
        this.iFaceShowListener = iFaceShowListener;
    }

    public String getCurrentPath() {
        return FaceFileUtil.getFilePath(getContext(), FACE2);
    }
}
